diff --git a/scripts/macros/rollDice.mjs b/scripts/macros/rollDice.mjs
index c4011eb..b6bebf9 100644
--- a/scripts/macros/rollDice.mjs
+++ b/scripts/macros/rollDice.mjs
@@ -1,17 +1,29 @@
async function rollDice() {
-
- const statBase = await DialogManager.ask({
- question: `How many dice to roll?`,
- initialValue: 2,
- inputType: `number`,
- });
-
- if (!statBase) {
- return;
- }
-
const sidesOnDice = 6;
- const successThreshold = 4;
+
+ const answers = await DialogManager.ask({
+ id: `eat-the-reich-dice-pool`,
+ question: `Set up your dice pool:`,
+ inputs: [
+ {
+ inputType: `number`,
+ defaultValue: 2,
+ label: `Number of Dice`,
+ autofocus: true,
+ },
+ {
+ inputType: `number`,
+ defaultValue: 4,
+ label: `Success Threshold (d${sidesOnDice} >= X)`,
+ },
+ {
+ inputType: `checkbox`,
+ defaultValue: true,
+ label: `Enable Criticals`,
+ },
+ ],
+ });
+ const [ statBase, successThreshold, critsEnabled ] = Object.values(answers);
let successes = 0;
const results = [];
@@ -22,14 +34,17 @@ async function rollDice() {
if (r.total >= successThreshold) {
successes++;
}
- if (r.total === sidesOnDice) {
+ if (r.total === sidesOnDice && critsEnabled) {
successes++;
}
}
- await ChatMessage.create({
+ const m = new ChatMessage({
+ title: `Dice Pool`,
content: `Rolled: ${results.join(`, `)}
Successes: ${successes}`,
});
+ m.applyRollMode(game.settings.get(`core`, `rollMode`));
+ ui.chat.postOne(m);
}
rollDice()
\ No newline at end of file
diff --git a/src/utils/DialogManager.mjs b/src/utils/DialogManager.mjs
index 56d1d9b..5dae6c8 100644
--- a/src/utils/DialogManager.mjs
+++ b/src/utils/DialogManager.mjs
@@ -79,49 +79,89 @@ export class DialogManager {
/**
* Asks the user to provide a simple piece of information, this is primarily
* intended to be used within macros so that it can have better info gathering
- * as needed.
+ * as needed. This returns an object of input labels to the value the user
+ * input for that label, if there is only one input, this will return the value
+ * without an object wrapper, allowing for easier access.
*/
static async ask(data, opts = {}) {
- if (!data.question) {
- throw new Error(`Asking the user for input must contain a question`);
+ if (!data.id) {
+ throw new Error(`Asking the user for input must contain an ID`);
+ }
+ if (!data.inputs.length) {
+ throw new Error(`Must include at least one input specification when prompting the user`);
}
- data.inputType ??= `text`;
- data.initialValue ??= ``;
- opts.title ??= `System Question`;
+ let autofocusClaimed = false;
+ for (const i of data.inputs) {
+ i.id ??= foundry.utils.randomID(16);
+ i.inputType ??= `text`;
+
+ // Only ever allow one input to claim autofocus
+ i.autofocus &&= !autofocusClaimed;
+ autofocusClaimed ||= i.autofocus;
+
+ // Set the value's attribute name if it isn't specified explicitly
+ if (!i.valueAttribute) {
+ switch (i.inputType) {
+ case `checkbox`:
+ i.valueAttribute = `checked`;
+ break;
+ default:
+ i.valueAttribute = `value`;
+ };
+ };
+ };
+
opts.jQuery = true;
+ data.default ??= `confirm`;
+ data.title ??= `System Question`;
- const content = await renderTemplate(
+ data.content = await renderTemplate(
`systems/${game.system.id}/templates/Dialogs/ask.hbs`,
data,
);
return new Promise((resolve, reject) => {
DialogManager.createOrFocus(
- data.question,
+ data.id,
{
- content,
+ ...data,
buttons: {
confirm: {
label: `Confirm`,
callback: (html) => {
- const element = html.find(`.user-input`)[0];
- let value = element.value;
- switch (data.inputType) {
- case `number`:
- value = parseFloat(value);
- break;
- case `checkbox`:
- value = element.checked;
- break;
+ const answers = {};
+
+ /*
+ Retrieve the answer for every input provided using the ID
+ determined during initial data prep, and assign the value
+ to the property of the label in the object.
+ */
+ for (const i of data.inputs) {
+ const element = html.find(`#${i.id}`)[0];
+ let value = element.value;
+ switch (i.inputType) {
+ case `number`:
+ value = parseFloat(value);
+ break;
+ case `checkbox`:
+ value = element.checked;
+ break;
+ }
+ Logger.debug(`Ask response: ${value} (type: ${typeof value})`);
+ answers[i.label] = value;
+ if (data.inputs.length === 1) {
+ resolve(value);
+ return;
+ }
}
- Logger.debug(`Ask response: ${value} (type: ${typeof value})`);
- resolve(value);
+
+ resolve(answers);
},
},
cancel: {
label: `Cancel`,
- callback: () => reject(),
+ callback: () => reject(`User cancelled the prompt`),
},
},
},
diff --git a/styles/v1/Dialog.scss b/styles/v1/Dialog.scss
index 9522789..28f133f 100644
--- a/styles/v1/Dialog.scss
+++ b/styles/v1/Dialog.scss
@@ -1,3 +1,12 @@
.dialog-content:not(:only-child) {
margin-bottom: 8px;
}
+
+.dialog-content {
+ p {
+ margin: 0;
+ }
+ .prompt {
+ margin-top: 8px;
+ }
+}
diff --git a/system.json b/system.json
index e9fde47..bf0ff7c 100644
--- a/system.json
+++ b/system.json
@@ -2,7 +2,7 @@
"id": "taf",
"title": "Text-Based Actors",
"description": "",
- "version": "1.0.0",
+ "version": "1.1.0",
"download": "https://github.com/Oliver-Akins/Text-Actors-Foundry/releases/latest/download/dotdungeon.zip",
"manifest": "https://github.com/Oliver-Akins/Text-Actors-Foundry/releases/latest/download/system.json",
"url": "https://github.com/Oliver-Akins/Text-Actors-Foundry",
diff --git a/templates/Dialogs/ask.hbs b/templates/Dialogs/ask.hbs
index d08d8a2..a37f56e 100644
--- a/templates/Dialogs/ask.hbs
+++ b/templates/Dialogs/ask.hbs
@@ -1,12 +1,27 @@
-
- {{question}} + {{ question }}
- + {{#each inputs as | i | }} ++ {{{ i.details }}} +
+ {{/if}} +