add spotlight request display on token option for GM
This commit is contained in:
parent
373b02a8fa
commit
e020a4efd7
4 changed files with 149 additions and 23 deletions
16
README.md
16
README.md
|
|
@ -6,15 +6,21 @@ A Foundry VTT v14 module that adds quality-of-life tweaks for the **Daggerheart*
|
|||
|
||||
### 1. Token HUD Spotlight (On by default)
|
||||
Adds a new Spotlight button directly to the default Token HUD menu:
|
||||
* **For Players**: Allows requesting or cancelling a spotlight request for their character.
|
||||
* **For GMs**: Allows granting spotlight to or removing spotlight from any token.
|
||||
* **Real-time Updates**: The HUD button automatically reflects status changes in real-time if updated via the combat tracker or other canvas actions.
|
||||
* **Works Everywhere**: Spotlight can be requested, granted, and taken both in and out of combat (an active encounter is not required).
|
||||
* **For Players**: Allows requesting or cancelling a spotlight request for their character. Out-of-combat requests are saved securely on the character actor.
|
||||
* **For GMs**: Allows granting spotlight to or removing spotlight from any token. Toggling spotlight on a token will automatically clear its active spotlight request.
|
||||
* **Real-time Updates**: The HUD button automatically reflects status changes in real-time if updated via the combat tracker, canvas settings, or other players.
|
||||
|
||||
### 2. Minimal Countdown UI (On by default)
|
||||
### 2. Spotlight Request Canvas Indicator (On by default)
|
||||
Displays a visual indicator on the canvas to make managing spotlight requests easier for the GM:
|
||||
* **For GMs**: Shows a small, gold hand-sparkles badge overlay in the top-right corner of any token that is currently requesting spotlight.
|
||||
* **Canvas Synchronization**: Instantly appears or disappears as players toggle their spotlight requests.
|
||||
|
||||
### 3. Minimal Countdown UI (On by default)
|
||||
Reduces screen clutter by optimizing the Countdown Tracker widget:
|
||||
* **For Players**: Hides the countdown widget completely if there are no active/visible countdowns.
|
||||
* **For GMs**: Minimizes the countdown widget to a tiny square featuring a `+` icon when empty. Clicking the `+` icon opens the system's native Countdown Edit dialog.
|
||||
|
||||
## Configuration
|
||||
|
||||
Both features can be toggled on or off independently under **Configure Settings** > **Cosmo's Daggerheart Tweaks**.
|
||||
All features can be toggled on or off independently under **Configure Settings** > **Cosmo's Daggerheart Tweaks**. The *Spotlight Request Canvas Indicator* is grouped together with the HUD button option.
|
||||
|
|
|
|||
|
|
@ -1,12 +1,13 @@
|
|||
{
|
||||
"COSMOS_DH_TWEAKS.Settings.TokenHudSpotlight.Name": "Token HUD Spotlight Button",
|
||||
"COSMOS_DH_TWEAKS.Settings.TokenHudSpotlight.Hint": "Add a Spotlight button to the Token HUD. Players can request/cancel spotlight, while GMs can grant/take it.",
|
||||
"COSMOS_DH_TWEAKS.Settings.SpotlightRequestIndicator.Name": "Spotlight Request Canvas Indicator",
|
||||
"COSMOS_DH_TWEAKS.Settings.SpotlightRequestIndicator.Hint": "For GMs, display a small hand icon overlay on tokens that are requesting spotlight.",
|
||||
"COSMOS_DH_TWEAKS.Settings.MinimalCountdownUI.Name": "Minimal Countdown UI",
|
||||
"COSMOS_DH_TWEAKS.Settings.MinimalCountdownUI.Hint": "When no countdowns are active, hides the UI completely for players and minimizes it to a '+' button for GMs.",
|
||||
"COSMOS_DH_TWEAKS.Spotlight.request": "Request Spotlight",
|
||||
"COSMOS_DH_TWEAKS.Spotlight.cancel": "Cancel Spotlight Request",
|
||||
"COSMOS_DH_TWEAKS.Spotlight.grant": "Grant Spotlight",
|
||||
"COSMOS_DH_TWEAKS.Spotlight.take": "Take Spotlight",
|
||||
"COSMOS_DH_TWEAKS.Spotlight.warnNoCombatant": "This token is not in combat. You can only request spotlight in combat.",
|
||||
"COSMOS_DH_TWEAKS.Countdown.add": "Add Countdown"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,10 +2,10 @@
|
|||
"id": "cosmos-dh-tweaks",
|
||||
"title": "Cosmo's Daggerheart Tweaks",
|
||||
"description": "A selection of quality of life tweaks for the Daggerheart system on Foundry VTT.",
|
||||
"version": "1.0.3",
|
||||
"version": "1.1.0",
|
||||
"url": "https://git.geeks.gay/cosmo/cosmos-dh-tweaks",
|
||||
"manifest": "https://git.geeks.gay/cosmo/cosmos-dh-tweaks/raw/branch/main/module.json",
|
||||
"download": "https://git.geeks.gay/cosmo/cosmos-dh-tweaks/releases/download/1.0.3/cosmos-dh-tweaks.zip",
|
||||
"download": "https://git.geeks.gay/cosmo/cosmos-dh-tweaks/releases/download/1.1.0/cosmos-dh-tweaks.zip",
|
||||
"compatibility": {
|
||||
"minimum": "14.000",
|
||||
"verified": "14.364"
|
||||
|
|
|
|||
|
|
@ -9,6 +9,23 @@ Hooks.once("init", () => {
|
|||
default: true
|
||||
});
|
||||
|
||||
game.settings.register("cosmos-dh-tweaks", "spotlightRequestIndicator", {
|
||||
name: "COSMOS_DH_TWEAKS.Settings.SpotlightRequestIndicator.Name",
|
||||
hint: "COSMOS_DH_TWEAKS.Settings.SpotlightRequestIndicator.Hint",
|
||||
scope: "world",
|
||||
config: true,
|
||||
type: Boolean,
|
||||
default: true,
|
||||
onChange: () => {
|
||||
if (canvas.ready) {
|
||||
for (const token of canvas.tokens.placeables) {
|
||||
if (token.refresh) token.refresh();
|
||||
else if (token.renderFlags) token.renderFlags.set({ refreshState: true });
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
game.settings.register("cosmos-dh-tweaks", "minimalCountdownUI", {
|
||||
name: "COSMOS_DH_TWEAKS.Settings.MinimalCountdownUI.Name",
|
||||
hint: "COSMOS_DH_TWEAKS.Settings.MinimalCountdownUI.Hint",
|
||||
|
|
@ -97,7 +114,9 @@ Hooks.on("renderTokenHUD", (tokenHUD, html, tokenData) => {
|
|||
// Players: only proceed if they own the token
|
||||
if (!token.document.isOwner) return;
|
||||
const combatant = token.combatant;
|
||||
active = combatant?.system.spotlight?.requesting || false;
|
||||
active = combatant
|
||||
? (combatant.system.spotlight?.requesting || false)
|
||||
: (token.actor?.getFlag("cosmos-dh-tweaks", "requestingSpotlight") || false);
|
||||
}
|
||||
|
||||
const title = isGM
|
||||
|
|
@ -154,13 +173,15 @@ Hooks.on("renderTokenHUD", (tokenHUD, html, tokenData) => {
|
|||
token.renderFlags.set({ refreshTurnMarker: true });
|
||||
}
|
||||
}
|
||||
|
||||
// Clear spotlight request indicator if GM grants/takes spotlight
|
||||
if (token.actor?.getFlag("cosmos-dh-tweaks", "requestingSpotlight")) {
|
||||
await token.actor.setFlag("cosmos-dh-tweaks", "requestingSpotlight", false);
|
||||
}
|
||||
} else {
|
||||
// Player requesting / cancelling spotlight
|
||||
const combatant = token.combatant;
|
||||
if (!combatant) {
|
||||
ui.notifications.warn(game.i18n.localize("COSMOS_DH_TWEAKS.Spotlight.warnNoCombatant"));
|
||||
return;
|
||||
}
|
||||
if (combatant) {
|
||||
const isRequesting = combatant.system.spotlight.requesting;
|
||||
const characters = game.combat.turns?.filter(x => !x.isNPC) ?? [];
|
||||
const orderValues = characters.map(character => character.system.spotlight.requestOrderIndex || 0);
|
||||
|
|
@ -172,6 +193,11 @@ Hooks.on("renderTokenHUD", (tokenHUD, html, tokenData) => {
|
|||
requestOrderIndex: !isRequesting ? maxRequestIndex + 1 : 0
|
||||
}
|
||||
});
|
||||
} else {
|
||||
// Out of combat request
|
||||
const isRequesting = !!token.actor?.getFlag("cosmos-dh-tweaks", "requestingSpotlight");
|
||||
await token.actor?.setFlag("cosmos-dh-tweaks", "requestingSpotlight", !isRequesting);
|
||||
}
|
||||
}
|
||||
|
||||
// Rerender HUD to update icon state
|
||||
|
|
@ -206,3 +232,96 @@ Hooks.on("updateSetting", (setting, change, options, userId) => {
|
|||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Trigger token refresh when Actor changes their requestingSpotlight flag
|
||||
Hooks.on("updateActor", (actor, change, options, userId) => {
|
||||
if (!game.ready) return;
|
||||
const tokens = actor.getActiveTokens();
|
||||
for (const token of tokens) {
|
||||
if (token.refresh) token.refresh();
|
||||
else if (token.renderFlags) token.renderFlags.set({ refreshState: true });
|
||||
}
|
||||
if (canvas.tokens.hud.rendered && canvas.tokens.hud.object?.actor?.id === actor.id) {
|
||||
canvas.tokens.hud.render(true);
|
||||
}
|
||||
});
|
||||
|
||||
// Trigger token refresh when Token changes
|
||||
Hooks.on("updateToken", (tokenDoc, change, options, userId) => {
|
||||
if (!game.ready) return;
|
||||
const token = tokenDoc.object;
|
||||
if (token) {
|
||||
if (token.refresh) token.refresh();
|
||||
else if (token.renderFlags) token.renderFlags.set({ refreshState: true });
|
||||
}
|
||||
if (canvas.tokens.hud.rendered && canvas.tokens.hud.object?.id === tokenDoc.id) {
|
||||
canvas.tokens.hud.render(true);
|
||||
}
|
||||
});
|
||||
|
||||
// Render the GM's spotlight request indicator on the token canvas
|
||||
Hooks.on("refreshToken", (token, options) => {
|
||||
if (!game.ready) return;
|
||||
if (!game.user?.isGM) return;
|
||||
if (!game.settings.get("cosmos-dh-tweaks", "tokenHudSpotlight")) return;
|
||||
if (!game.settings.get("cosmos-dh-tweaks", "spotlightRequestIndicator")) {
|
||||
if (token.cosmoSpotlightIndicator) {
|
||||
token.cosmoSpotlightIndicator.visible = false;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
const inCombat = !!token.combatant;
|
||||
const requestingInCombat = token.combatant?.system.spotlight?.requesting;
|
||||
const requestingOutOfCombat = token.actor?.getFlag("cosmos-dh-tweaks", "requestingSpotlight");
|
||||
const isRequesting = inCombat ? requestingInCombat : requestingOutOfCombat;
|
||||
|
||||
if (isRequesting) {
|
||||
// Safe check to reconstruct if it was destroyed or detached
|
||||
const isDestroyed = token.cosmoSpotlightIndicator && (token.cosmoSpotlightIndicator.destroyed || !token.children.includes(token.cosmoSpotlightIndicator));
|
||||
if (isDestroyed) {
|
||||
token.cosmoSpotlightIndicator = null;
|
||||
}
|
||||
|
||||
if (!token.cosmoSpotlightIndicator) {
|
||||
const container = new PIXI.Container();
|
||||
container.name = "cosmoSpotlightIndicator";
|
||||
|
||||
// Draw a background circle (gold)
|
||||
const bg = new PIXI.Graphics();
|
||||
bg.beginFill(0xc5a45e, 0.9);
|
||||
bg.lineStyle(1.5, 0xffffff, 1);
|
||||
bg.drawCircle(0, 0, 11);
|
||||
bg.endFill();
|
||||
container.addChild(bg);
|
||||
|
||||
// Draw FontAwesome solid e05d hand sparkles icon
|
||||
const style = new PIXI.TextStyle({
|
||||
fontFamily: '"Font Awesome 6 Free"',
|
||||
fontWeight: "900",
|
||||
fontSize: 13,
|
||||
fill: "#ffffff"
|
||||
});
|
||||
const text = new PIXI.Text("\ue05d", style);
|
||||
text.anchor.set(0.5);
|
||||
container.addChild(text);
|
||||
|
||||
token.cosmoSpotlightIndicator = token.addChild(container);
|
||||
}
|
||||
|
||||
// Position the indicator at the top-right of the token container
|
||||
const size = token.w || 50;
|
||||
token.cosmoSpotlightIndicator.position.set(size - 10, 10);
|
||||
token.cosmoSpotlightIndicator.visible = true;
|
||||
} else {
|
||||
if (token.cosmoSpotlightIndicator) {
|
||||
token.cosmoSpotlightIndicator.visible = false;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
Hooks.on("destroyToken", (token) => {
|
||||
if (token.cosmoSpotlightIndicator) {
|
||||
token.cosmoSpotlightIndicator = null;
|
||||
}
|
||||
});
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue