https://github.com/foundryvtt/unfulfilled-rolls
A module that allows individual rolls to be fulfilled by other sources
https://github.com/foundryvtt/unfulfilled-rolls
foundryvtt
Last synced: 6 months ago
JSON representation
A module that allows individual rolls to be fulfilled by other sources
- Host: GitHub
- URL: https://github.com/foundryvtt/unfulfilled-rolls
- Owner: foundryvtt
- License: mit
- Created: 2023-03-16T23:32:01.000Z (over 3 years ago)
- Default Branch: master
- Last Pushed: 2024-01-15T16:10:30.000Z (over 2 years ago)
- Last Synced: 2024-01-15T20:59:30.996Z (over 2 years ago)
- Topics: foundryvtt
- Language: JavaScript
- Homepage:
- Size: 68.4 KB
- Stars: 2
- Watchers: 2
- Forks: 3
- Open Issues: 16
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README

# Unfulfilled Rolls
Allows individual rolls to be fulfilled by other sources
## Configuring per-die resolution methods
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).

## An example roll
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
```json
[
{
"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
```json
{
"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
}
```
## Registering a new Provider
Currently only bluetooth providers are supported, but more types can be added fairly easily by following the pattern bluetooth providers uses.
```js
Hooks.once('unfulfilled-rolls-bluetooth', function(providers) {
return foundry.utils.mergeObject(providers, {
"godice": {
label: "GoDice",
app: GodiceResolver
}
})
});
```
### Implementing a Provider
Each provider needs to register an application to handle the roll resolution. Here is a simplified example:
```js
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);
}
}
```