mirror of
https://github.com/Foundryborne/daggerheart.git
synced 2026-07-21 18:09:54 +02:00
Added handling for ComboDice single dice reroll
This commit is contained in:
parent
2d6c442421
commit
a285b3f4dc
1 changed files with 154 additions and 70 deletions
|
|
@ -1,7 +1,14 @@
|
||||||
import { adjustDice } from '../../helpers/utils.mjs';
|
import { adjustDice, triggerChatRollFx } from '../../helpers/utils.mjs';
|
||||||
|
|
||||||
export default class BaseDie extends foundry.dice.terms.Die {
|
export default class BaseDie extends foundry.dice.terms.Die {
|
||||||
async rerollResult(resultIndex) {
|
static MODIFIERS = {
|
||||||
|
...foundry.dice.terms.Die.MODIFIERS,
|
||||||
|
cc: 'compoundComboDice',
|
||||||
|
c: 'comboDice'
|
||||||
|
};
|
||||||
|
|
||||||
|
async rerollResult(resultToReroll) {
|
||||||
|
const resultIndex = Number(resultToReroll);
|
||||||
const result = this.results[resultIndex];
|
const result = this.results[resultIndex];
|
||||||
result.rerolled = true;
|
result.rerolled = true;
|
||||||
result.active = false;
|
result.active = false;
|
||||||
|
|
@ -10,75 +17,10 @@ export default class BaseDie extends foundry.dice.terms.Die {
|
||||||
const rerolledResult = this.results[this.results.length - 1];
|
const rerolledResult = this.results[this.results.length - 1];
|
||||||
this.results.splice(this.results.length - 1, 1);
|
this.results.splice(this.results.length - 1, 1);
|
||||||
this.results.splice(resultIndex, 0, rerolledResult);
|
this.results.splice(resultIndex, 0, rerolledResult);
|
||||||
}
|
|
||||||
|
|
||||||
static MODIFIERS = {
|
if (['c', 'cc'].some(x => this.modifiers.includes(x))) {
|
||||||
...foundry.dice.terms.Die.MODIFIERS,
|
await this.handleComboDiceReroll(resultIndex);
|
||||||
cc: 'compoundComboDice',
|
}
|
||||||
c: 'comboDice'
|
|
||||||
};
|
|
||||||
|
|
||||||
async compoundComboDice() {
|
|
||||||
return this.handleComboDice(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
async comboDice() {
|
|
||||||
return this.handleComboDice(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
async handleComboDice(maxIncreasesDiceSize) {
|
|
||||||
/* ComboDice only works with exactly two dice and both have to be the same denomination */
|
|
||||||
if (this.number !== 2) {
|
|
||||||
ui.notifications.warn(game.i18n.localize('DAGGERHEART.UI.Notifications.comboDiceOnlyTwoDiceError'));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const result = await this.continueCombo(maxIncreasesDiceSize);
|
|
||||||
|
|
||||||
/* The flow of DiceSoNice has no way of knowign that some of the results of a Die should be a different denomination
|
|
||||||
We solve this by marking the results as hidden so they're not picked up by the auto roll of DiceSoNice.
|
|
||||||
The actual rolls are done here in place so every dice gets the correct denomination.
|
|
||||||
*/
|
|
||||||
if (game.modules.get('dice-so-nice')?.active) {
|
|
||||||
const rolls = [];
|
|
||||||
for (const result of this.results) {
|
|
||||||
const roll = await (new Roll(`1${result.denomination ?? this.denomination}`)).evaluate();
|
|
||||||
roll.terms[0].results = [result];
|
|
||||||
roll._evaluateTotal();
|
|
||||||
rolls.push(roll);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* If there are other dice that will be rolled we cannot await here. The other dice will be awaited in the normal flow */
|
|
||||||
if (this._root.dice.length > 1) {
|
|
||||||
for (const roll of rolls) {
|
|
||||||
game.dice3d.showForRoll(roll, game.user, true);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
await Promise.allSettled(rolls.map(roll => game.dice3d.showForRoll(roll, game.user, true)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const result of this.results)
|
|
||||||
result.hidden = true;
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
async continueCombo(maxIncreasesDiceSize) {
|
|
||||||
const lastIndex = this.results.length - 1;
|
|
||||||
|
|
||||||
/* The Combo only continues if the latest roll was higher or equal to the previous */
|
|
||||||
if (this.results[lastIndex].result < this.results[lastIndex - 1].result) return false;
|
|
||||||
|
|
||||||
const lastFaces = this.results[lastIndex].denomination?.slice(1) ?? this.faces;
|
|
||||||
const increaseDiceSize = maxIncreasesDiceSize && lastFaces < 12 && this.results[lastIndex].result === lastFaces;
|
|
||||||
const denomination = increaseDiceSize ? adjustDice(this.denomination, false) : this.denomination;
|
|
||||||
|
|
||||||
const newRoll = await (new Roll(`1${denomination}`)).evaluate();
|
|
||||||
this.results.push({ result: newRoll.total, denomination: denomination, active: true });
|
|
||||||
this.number += 1;
|
|
||||||
|
|
||||||
return this.continueCombo(maxIncreasesDiceSize);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @override */
|
/** @override */
|
||||||
|
|
@ -99,4 +41,146 @@ export default class BaseDie extends foundry.dice.terms.Die {
|
||||||
!(hasSuccess || hasFailure) && isMax ? 'max' : null
|
!(hasSuccess || hasFailure) && isMax ? 'max' : null
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------------- */
|
||||||
|
/* Modifier Logic */
|
||||||
|
/* -------------------------------------------- */
|
||||||
|
|
||||||
|
async compoundComboDice() {
|
||||||
|
return this.handleComboDice({ maxIncreasesDiceSize: true});
|
||||||
|
}
|
||||||
|
|
||||||
|
async comboDice() {
|
||||||
|
return this.handleComboDice({ maxIncreasesDiceSize: false });
|
||||||
|
}
|
||||||
|
|
||||||
|
async handleComboDice(maxIncreasesDiceSize) {
|
||||||
|
/* ComboDice only works with exactly two dice and both have to be the same denomination */
|
||||||
|
if (this.number !== 2) {
|
||||||
|
ui.notifications.warn(game.i18n.localize('DAGGERHEART.UI.Notifications.comboDiceOnlyTwoDiceError'));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.rollComboDice(maxIncreasesDiceSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
async rollComboDice(options) {
|
||||||
|
const { maxIncreasesDiceSize, rerollStartIndex } = options;
|
||||||
|
const initialResultsLength = this.results.length;
|
||||||
|
const result = await this.continueCombo(maxIncreasesDiceSize);
|
||||||
|
|
||||||
|
/* The flow of DiceSoNice has no way of knowing that some of the results of a Die should be a different denomination
|
||||||
|
We solve this by marking the results as hidden so they're not picked up by the auto roll of DiceSoNice.
|
||||||
|
The actual rolls are done here in place so every dice gets the correct denomination.
|
||||||
|
*/
|
||||||
|
if (game.modules.get('dice-so-nice')?.active) {
|
||||||
|
const resultsToRoll = this.results.filter((x, index) => {
|
||||||
|
if (!x.active) return false;
|
||||||
|
if (rerollStartIndex)
|
||||||
|
return index === rerollStartIndex || index > initialResultsLength - 1;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
const rolls = [];
|
||||||
|
for (const result of resultsToRoll) {
|
||||||
|
const roll = await (new Roll(`1${result.denomination ?? this.denomination}`)).evaluate();
|
||||||
|
roll.terms[0].results = [result];
|
||||||
|
roll._evaluateTotal();
|
||||||
|
rolls.push(roll);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If there are other dice that will be rolled we cannot await here. The other dice will be awaited in the normal flow */
|
||||||
|
if (rerollStartIndex === undefined && this._root.dice.length > 1) {
|
||||||
|
for (const roll of rolls) {
|
||||||
|
game.dice3d.showForRoll(roll, game.user, true);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
await Promise.allSettled(rolls.map(roll => game.dice3d.showForRoll(roll, game.user, true)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const result of this.results)
|
||||||
|
result.hidden = true;
|
||||||
|
|
||||||
|
const modifier = maxIncreasesDiceSize ? 'cc' : 'c';
|
||||||
|
if (!this.modifiers.includes(modifier))
|
||||||
|
this.modifiers.push(modifier);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
async continueCombo(maxIncreasesDiceSize) {
|
||||||
|
const activeResults = this.results.filter(x => x.active);
|
||||||
|
const lastIndex = activeResults.length - 1;
|
||||||
|
|
||||||
|
/* The Combo only continues if the latest roll was higher or equal to the previous */
|
||||||
|
if (activeResults[lastIndex].result < activeResults[lastIndex - 1].result) return false;
|
||||||
|
|
||||||
|
const lastFaces = activeResults[lastIndex].denomination?.slice(1) ?? this.faces;
|
||||||
|
const increaseDiceSize =
|
||||||
|
maxIncreasesDiceSize && lastFaces < 12 &&
|
||||||
|
activeResults[lastIndex].result === lastFaces;
|
||||||
|
const denomination = increaseDiceSize ? adjustDice(this.denomination, false) : this.denomination;
|
||||||
|
|
||||||
|
const newRoll = await (new Roll(`1${denomination}`)).evaluate();
|
||||||
|
this.results.push({ result: newRoll.total, denomination: denomination, active: true });
|
||||||
|
this.number += 1;
|
||||||
|
|
||||||
|
return this.continueCombo(maxIncreasesDiceSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
async handleComboDiceReroll(rerolledIndex) {
|
||||||
|
const resultGroupingIndexes = this.results.map((x, index) => ({ index, active: x.active }))
|
||||||
|
.filter(x => x.active).map(x => x.index);
|
||||||
|
if (resultGroupingIndexes.length <= 1) return;
|
||||||
|
|
||||||
|
const rerolledResult = this.results[rerolledIndex];
|
||||||
|
const compoundCombo = this.modifiers.includes('cc');
|
||||||
|
const rerollGroupingIndex = resultGroupingIndexes.indexOf(rerolledIndex);
|
||||||
|
|
||||||
|
const previousIndex = resultGroupingIndexes[rerollGroupingIndex - 1];
|
||||||
|
const previousResult = this.results[previousIndex];
|
||||||
|
const nextIndex = resultGroupingIndexes[rerollGroupingIndex + 1];
|
||||||
|
const nextResult = this.results[nextIndex];
|
||||||
|
|
||||||
|
/* Rerolling any of the last two dice might introduce new results */
|
||||||
|
if (
|
||||||
|
rerollGroupingIndex === resultGroupingIndexes.length - 1 &&
|
||||||
|
rerolledResult.result >= previousResult?.result
|
||||||
|
) {
|
||||||
|
return await this.rollComboDice({
|
||||||
|
maxIncreasesDiceSize: compoundCombo,
|
||||||
|
rerollStartIndex: rerollGroupingIndex
|
||||||
|
});
|
||||||
|
} else if (
|
||||||
|
rerollGroupingIndex === resultGroupingIndexes.length - 2 &&
|
||||||
|
rerolledResult.result < nextResult?.result
|
||||||
|
) {
|
||||||
|
return await this.rollComboDice({
|
||||||
|
maxIncreasesDiceSize: compoundCombo,
|
||||||
|
rerollStartIndex: rerollGroupingIndex
|
||||||
|
});
|
||||||
|
}
|
||||||
|
/* Rerolling a preceeding dice might invalidate later dice which should then be dropped */
|
||||||
|
else if (rerolledResult.result < previousResult?.result){
|
||||||
|
const cutoffIndex = rerollGroupingIndex === 0 ? resultGroupingIndexes[1] + 1 : rerolledIndex + 1;
|
||||||
|
this.results = this.results.slice(0, cutoffIndex);
|
||||||
|
this.number = this.results.filter(x => x.active).length;
|
||||||
|
}
|
||||||
|
|
||||||
|
const fakeRollFaces =
|
||||||
|
rerolledResult.denomination ? rerolledResult.denomination.slice(1) : this.faces;
|
||||||
|
const fakeRoll = {
|
||||||
|
_evaluated: true,
|
||||||
|
dice: [new foundry.dice.terms.Die({
|
||||||
|
...this,
|
||||||
|
results: [rerolledResult],
|
||||||
|
total: rerolledResult.result,
|
||||||
|
faces: fakeRollFaces
|
||||||
|
})],
|
||||||
|
options: { appearance: {} }
|
||||||
|
};
|
||||||
|
await triggerChatRollFx([fakeRoll]);
|
||||||
|
rerolledResult.hidden = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue