Allows individual rolls to be fulfilled by other sources
A new Sidebar app is added called "Open Dice Configuration"
In this app, each User (client setting) may pick how each die is resolved - via Foundry VTT digital rolling, via manual input, or via a bluetooth provider - as well as what Bluetooth provider they are using (requires a separate module install for the bluetooth provider, such as the GoDice module).
In this example, d20's and d8's are configured for Bluetooth resolution, while d4 is Foundry VTT Digital Roll.
/roll 2d20 + d8 + d4 + 4
Unfulfilled rolls works with the Foundry VTT dice rolling workflow to determine that there are terms that need resolution (the 2d20 and the d8), and displays a window - note that it gives the full roll for context, but only prompts resolution of the ones marked
Inside of the resolution app, the following two parameters are given:
terms
The array of terms that need to be fulfilled
[
{
"id": "d20-1",
"faces": 20,
"randomValue": 12,
"fulfillmentMethod": "bluetooth",
"icon": "fa-dice-d20"
},
{
"id": "d20-2",
"faces": 20,
"randomValue": 17,
"fulfillmentMethod": "bluetooth",
"icon": "fa-dice-d20"
},
{
"id": "d8-1",
"faces": 8,
"randomValue": 7,
"fulfillmentMethod": "bluetooth",
"icon": "fa-dice-d8"
}
]
roll
The originating Roll
{
"class": "FulfillableRoll",
"options": {},
"dice": [],
"formula": "2d20 + d8 + d4 + 4",
"terms": [
{
"class": "FulfillableRollTerm",
"options": {},
"evaluated": false,
"number": 2,
"faces": 20,
"modifiers": [],
"results": []
},
{
"class": "OperatorTerm",
"options": {},
"evaluated": false,
"operator": "+"
},
{
"class": "FulfillableRollTerm",
"options": {},
"evaluated": false,
"number": 1,
"faces": 8,
"modifiers": [],
"results": []
},
{
"class": "OperatorTerm",
"options": {},
"evaluated": false,
"operator": "+"
},
{
"class": "FulfillableRollTerm",
"options": {},
"evaluated": false,
"number": 1,
"faces": 4,
"modifiers": [],
"results": []
},
{
"class": "OperatorTerm",
"options": {},
"evaluated": false,
"operator": "+"
},
{
"class": "NumericTerm",
"options": {},
"evaluated": false,
"number": 4
}
],
"evaluated": true
}
Currently only bluetooth providers are supported, but more types can be added fairly easily by following the pattern bluetooth providers uses.
Hooks.once('unfulfilled-rolls-bluetooth', function(providers) {
return foundry.utils.mergeObject(providers, {
"godice": {
label: "GoDice",
app: GodiceResolver
}
})
});
Each provider needs to register an application to handle the roll resolution. Here is a simplified example:
export default class ExampleResolver extends FormApplication {
constructor(terms, roll, callback) {
super({});
this.terms = terms;
this.roll = roll;
this.callback = callback;
}
/* -------------------------------------------- */
static get defaultOptions() {
return foundry.utils.mergeObject(super.defaultOptions, {
id: "example-resolver",
template: "modules/example/templates/example-resolver.hbs",
title: "Example Resolver",
popOut: true,
width: 720,
submitOnChange: false,
submitOnClose: true,
closeOnSubmit: true
});
}
/* -------------------------------------------- */
/** @override */
async getData(options={}) {
const context = await super.getData(options);
context.terms = this.terms;
context.roll = this.roll;
return context;
}
/* -------------------------------------------- */
/** @override */
async _updateObject(event, formData) {
// Turn the entries into a map
const fulfilled = new Map();
for ( const [id, result] of Object.entries(formData) ) {
// Parse the result as a number
fulfilled.set(id, Number(result));
}
this.callback(fulfilled);
}
}