diff --git a/module.json b/module.json index fd7e8d6..3d6bcf0 100644 --- a/module.json +++ b/module.json @@ -4,8 +4,8 @@ "description": "Adds a button to the token hover HUD to toggle the spotlight for Daggerheart.", "url": "https://git.geeks.gay/cosmo/dh-token-spotlight", "manifest": "https://git.geeks.gay/cosmo/dh-token-spotlight/raw/branch/main/module.json", - "download": "https://git.geeks.gay/cosmo/dh-token-spotlight/releases/download/1.0.0/dh-token-spotlight.zip", - "version": "1.0.0", + "download": "https://git.geeks.gay/cosmo/dh-token-spotlight/releases/download/1.1.1/dh-token-spotlight.zip", + "version": "1.1.1", "compatibility": { "minimum": "13", "verified": "13" @@ -33,7 +33,5 @@ ], "styles": [ "styles/styles.css" - ], - "manifest": "", - "download": "" + ] } \ No newline at end of file diff --git a/scripts/main.js b/scripts/main.js index 8b2ee9d..64e6b71 100644 --- a/scripts/main.js +++ b/scripts/main.js @@ -7,43 +7,91 @@ Hooks.on('renderTokenHUD', (app, html, data) => { // In Daggerheart, the combatant with the spotlight is the one whose turn it currently is. const hasSpotlight = viewedCombat.combatant?.id === token.combatant.id; + const isRequesting = token.combatant.system?.spotlight?.requesting; // Determine icon and classes based on spotlight state - const iconClass = hasSpotlight - ? "fa-solid fa-hand-sparkles dh-spotlight-glow" - : "fa-regular fa-hand-sparkles"; + let iconClass = "fa-regular fa-hand-sparkles"; + let activeClass = ""; + if (hasSpotlight) { + iconClass = "fa-solid fa-hand-sparkles dh-spotlight-glow"; + activeClass = "active"; + } else if (isRequesting) { + iconClass = "fa-solid fa-hand-sparkles dh-spotlight-request"; + activeClass = "active"; + } + let tooltipText = ""; + if (game.user.isGM) { + tooltipText = hasSpotlight ? "Take Spotlight" : "Grant Spotlight"; + } else { + tooltipText = hasSpotlight ? "Remove Spotlight" : (isRequesting ? "Cancel Spotlight Request" : "Request Spotlight"); + } + const buttonHtml = ` -
+
`; // Append to the right column of the Token HUD - const colRight = html.find('.col.right'); + const colRight = $(html).find('.col.right'); colRight.append(buttonHtml); // Add click listener - html.find('[data-action="toggle-spotlight"]').click(async event => { + $(html).find('[data-action="toggle-spotlight"]').click(async event => { event.preventDefault(); event.stopPropagation(); - if (ui.combat && typeof ui.combat.setCombatantSpotlight === "function") { + if (ui.combat) { const btn = $(event.currentTarget); const icon = btn.find('i'); const wasActive = btn.hasClass('active'); + const isRequestingMsg = icon.hasClass('dh-spotlight-request'); - // Optimistic UI update - if (wasActive) { - btn.removeClass('active'); - icon.removeClass('fa-solid dh-spotlight-glow').addClass('fa-regular'); + if (game.user.isGM) { + if (typeof ui.combat.setCombatantSpotlight === "function") { + // Optimistic UI update for GM + if (wasActive && !isRequestingMsg) { + btn.removeClass('active'); + icon.removeClass('fa-solid dh-spotlight-glow').addClass('fa-regular'); + btn.attr('title', 'Grant Spotlight'); + } else { + btn.addClass('active'); + icon.removeClass('fa-regular dh-spotlight-request').addClass('fa-solid dh-spotlight-glow'); + btn.attr('title', 'Take Spotlight'); + } + await ui.combat.setCombatantSpotlight(token.combatant.id); + } } else { - btn.addClass('active'); - icon.removeClass('fa-regular').addClass('fa-solid dh-spotlight-glow'); + // Players request the spotlight + const combat = ui.combat.viewed; + if (!combat) return; + + const characters = combat.turns?.filter(x => !x.isNPC) ?? []; + // Fallback to maxRequestIndex = 0 if necessary + const orderValues = characters.map(c => c.system?.spotlight?.requestOrderIndex || 0); + const maxRequestIndex = orderValues.length > 0 ? Math.max(...orderValues) : 0; + + const currentlyRequesting = !!token.combatant.system?.spotlight?.requesting; + + // Optimistic UI update for Player + if (currentlyRequesting) { + btn.removeClass('active'); + icon.removeClass('fa-solid dh-spotlight-request').addClass('fa-regular'); + btn.attr('title', 'Request Spotlight'); + } else { + btn.addClass('active'); + icon.removeClass('fa-regular').addClass('fa-solid dh-spotlight-request'); + btn.attr('title', 'Cancel Spotlight Request'); + } + + await token.combatant.update({ + 'system.spotlight': { + requesting: !currentlyRequesting, + requestOrderIndex: !currentlyRequesting ? maxRequestIndex + 1 : 0 + } + }); } - - // Call the system's spotlight toggle function - await ui.combat.setCombatantSpotlight(token.combatant.id); } else { ui.notifications.warn("System does not support spotlight or combat is not initialized."); } diff --git a/styles/styles.css b/styles/styles.css index 4e9e11d..f4f02d3 100644 --- a/styles/styles.css +++ b/styles/styles.css @@ -8,3 +8,16 @@ #token-hud .control-icon.active i.dh-spotlight-glow { color: #ffd700; } + +/* Vertically center the generic FontAwesome icon */ +#token-hud .control-icon[data-action="toggle-spotlight"] { + display: flex; + justify-content: center; + align-items: center; +} + +/* Player spotlight request effect */ +#token-hud .control-icon.active i.dh-spotlight-request { + color: #4da6ff; + text-shadow: 0 0 5px #007bff, 0 0 10px #007bff; +}