diff --git a/README.md b/README.md new file mode 100644 index 0000000..55f36bd --- /dev/null +++ b/README.md @@ -0,0 +1,25 @@ +# Duality Dice Roller (Foundry VTT v13 Module) + +A simple Foundry VTT module that adds a custom **"Duality Dice Roller"** button to the chat controls. +Clicking the button automatically runs the `/dr` chat command. + +--- + +## ✨ Features +- Adds a new dice button with a custom SVG icon made byt he awesome @UsernameIsInUse. +- One-click execution of `/dr`. + +--- + +## 📦 Installation + +1. In Foundry VTT, go to **Settings → Add-on Modules → Install Module**. +2. Paste this manifest link: `https://raw.githubusercontent.com/cptn_cosmo/DualityDiceRoller/main/module.json` +3. Enable the module in **World Settings → Manage Modules**. + +--- + +## 🔨 Usage +- Open the chat log. +- Look for the **Duality Dice Roller** button (🎲 custom dice icon). +- Click it → `/dr` command runs automatically in chat. diff --git a/module.json b/module.json new file mode 100644 index 0000000..f95fa35 --- /dev/null +++ b/module.json @@ -0,0 +1,20 @@ +{ + "id": "duality-roller", + "title": "Duality Dice Roller", + "description": "Adds a button next to the chat dice/controls that triggers the /dr command for the Foundryborne Daggerheart system.", + "version": "1.0.0", + "compatibility": { + "minimum": "13", + "verified": "13" + }, + "authors": [ + { "name": "cptn_cosmo" } + ], + "esmodules": ["scripts/dr-button.js"], + "styles": ["styles/dr-button.css"], + "packs": [], + "languages": [], + "url": "https://github.com/cptn-cosmo/DualityDiceRoller", + "manifest": "https://raw.githubusercontent.com/cptn_cosmo/DualityDiceRoller/main/module.json", + "download": "https://github.com/cptn-cosmo/DualityDiceRoller/releases" +} diff --git a/scripts/dr-button.js b/scripts/dr-button.js new file mode 100644 index 0000000..ce87b12 --- /dev/null +++ b/scripts/dr-button.js @@ -0,0 +1,110 @@ +/** + * DR Quick Button — Foundry VTT v13 + * Adds a button near the chat dice/controls that runs the `/dr` command. + */ + +Hooks.once("init", () => { + console.log("DR Quick Button | Initializing"); +}); + +// Sidebar chat +Hooks.on("renderChatLog", (app, html) => addDRButton(html)); + +// Mini/Popout chat +Hooks.on("renderChatPopout", (app, html) => addDRButton(html)); + +function addDRButton(html) { + try { + // Avoid duplicates + if (html.querySelector(".dr-quick-button")) return; + + const container = + html.querySelector(".dice-tray") || + html.querySelector(".chat-controls .control-buttons") || + html.querySelector(".chat-controls") || + html; + + // Build button + const btn = document.createElement("button"); + btn.type = "button"; + btn.className = "dr-quick-button"; + btn.title = "Duality Dice Roll"; + btn.setAttribute("aria-label", "Duality Dice Roll"); + + // Inline SVG (or use icon.src = "modules/dr-quick-button/icons/dr.svg"; if external) + btn.innerHTML = ` + + + + + + + + + + + + + + + + + + + `; + + btn.addEventListener("click", async () => { + await runDRCommand(); + }); + + // Insert as the 5th button in the row (index 4, since it's 0-based) + const buttons = container.querySelectorAll("button"); + if (buttons.length >= 4) { + container.insertBefore(btn, buttons[4]); // before the current 5th button + } else { + container.appendChild(btn); // fallback if fewer than 4 buttons + } + } catch (err) { + console.error("DR Quick Button | addDRButton error:", err); + } +} + + +/** Run `/dr` as if typed into chat */ +async function runDRCommand() { + const cmd = "/dr"; + + try { + if (ui?.chat?.processMessage) return await ui.chat.processMessage(cmd); + } catch (e) { + console.warn("DR Quick Button | ui.chat.processMessage failed:", e); + } + + try { + if (globalThis.ChatLog?.instance?.processMessage) { + return await globalThis.ChatLog.instance.processMessage(cmd); + } + } catch (e) { + console.warn("DR Quick Button | ChatLog.instance.processMessage failed:", e); + } + + try { + const form = ui.chat?.element?.querySelector?.("form#chat-form"); + const textarea = form?.querySelector?.("textarea[name='message']"); + if (form && textarea) { + const prev = textarea.value; + textarea.value = cmd; + form.dispatchEvent(new Event("submit", { bubbles: true, cancelable: true })); + setTimeout(() => (textarea.value = prev ?? ""), 0); + return; + } + } catch (e) { + console.warn("DR Quick Button | Fallback submit failed:", e); + } + + ui.notifications?.warn?.("Couldn't run /dr automatically. Try typing /dr in chat."); +} diff --git a/styles/dr-button.css b/styles/dr-button.css new file mode 100644 index 0000000..dabe6d5 --- /dev/null +++ b/styles/dr-button.css @@ -0,0 +1,24 @@ +/* Keep it visually consistent with Foundry's small dice/controls buttons */ +.dr-quick-button { + display: inline-flex; + align-items: center; + justify-content: center; + width: 28px; + height: 28px; + margin-left: 4px; + border: 1px solid var(--color-border-light-2, #8882); + border-radius: 4px; + background: var(--color-bg, #222e); + cursor: pointer; + padding: 1; +} + +.dr-quick-button:hover { + filter: brightness(1.15); +} + +.dr-quick-button img { + width: 18px; + height: 18px; + pointer-events: none; +}