Compare commits

...

2 commits
2.0.0 ... main

4 changed files with 104 additions and 11 deletions

View file

@ -45,8 +45,16 @@
"CarouselSpeedHint": "Sekunden, die jede Karte angezeigt wird, bevor gewechselt wird.", "CarouselSpeedHint": "Sekunden, die jede Karte angezeigt wird, bevor gewechselt wird.",
"CarouselEffect": "Übergangseffekt", "CarouselEffect": "Übergangseffekt",
"CarouselEffectHint": "Animationseffekt beim Wechseln der Karten.", "CarouselEffectHint": "Animationseffekt beim Wechseln der Karten.",
"CarouselDisableFade": "Verblassen für Slide-Effekt deaktivieren",
"CarouselDisableFadeHint": "Wenn aktiviert und der 'Gleiten' Effekt gewählt ist, bleiben die Karten während des Übergangs voll sichtbar (Klassisches Karussell).",
"CarouselTransitionDuration": "Übergangsdauer (ms)",
"CarouselTransitionDurationHint": "Wie lange die Animation dauert (Standard: 800ms).",
"CarouselGMMode": "GM Karussell-Verhalten", "CarouselGMMode": "GM Karussell-Verhalten",
"CarouselGMModeHint": "Wie der GM im Karussell behandelt werden soll." "CarouselGMModeHint": "Wie der GM im Karussell dargestellt werden soll.",
"CarouselHidePlayers": "Spieler im Karussell verbergen",
"CarouselHidePlayersHint": "Wenn aktiviert, werden Spielercharaktere nicht im Karussell angezeigt.",
"CarouselHidePartyActor": "Party-Actor im Karussell verbergen",
"CarouselHidePartyActorHint": "Wenn aktiviert, werden Actors vom Typ 'Party' nicht im Karussell angezeigt."
}, },
"OpenStream": "Stream-Ansicht öffnen", "OpenStream": "Stream-Ansicht öffnen",
"ModeNumeric": "Numerisch (3/6)", "ModeNumeric": "Numerisch (3/6)",

View file

@ -53,8 +53,16 @@
"CarouselSpeedHint": "Seconds to show each player card before switching.", "CarouselSpeedHint": "Seconds to show each player card before switching.",
"CarouselEffect": "Transition Effect", "CarouselEffect": "Transition Effect",
"CarouselEffectHint": "Animation effect when switching cards.", "CarouselEffectHint": "Animation effect when switching cards.",
"CarouselDisableFade": "Disable Fade for Slide Effect",
"CarouselDisableFadeHint": "If enabled and using 'Slide' effect, cards will maintain full opacity during transition (Classic Carousel).",
"CarouselTransitionDuration": "Transition Duration (ms)",
"CarouselTransitionDurationHint": "How long the animation takes (Default: 800ms).",
"CarouselGMMode": "GM Carousel Behavior", "CarouselGMMode": "GM Carousel Behavior",
"CarouselGMModeHint": "How the GM should constitute in the carousel." "CarouselGMModeHint": "How the GM should constitute in the carousel.",
"CarouselHidePlayers": "Hide Players in Carousel",
"CarouselHidePlayersHint": "If enabled, party actors (players) will not be shown in the carousel.",
"CarouselHidePartyActor": "Hide 'Party' Actor in Carousel",
"CarouselHidePartyActorHint": "If enabled, actors with the type 'Party' will not be shown in the carousel."
}, },
"OpenStream": "Open Stream View", "OpenStream": "Open Stream View",
"ModeNumeric": "Numeric (3/6)", "ModeNumeric": "Numeric (3/6)",

View file

@ -1,7 +1,7 @@
{ {
"id": "dh-stream-overlay", "id": "dh-stream-overlay",
"title": "Daggerheart Stream Overlay", "title": "Daggerheart Stream Overlay",
"version": "2.0.0", "version": "2.1.0",
"compatibility": { "compatibility": {
"minimum": "13", "minimum": "13",
"verified": "13" "verified": "13"
@ -45,6 +45,6 @@
"packFolders": [], "packFolders": [],
"url": "https://github.com/cptn-cosmo/dh-stream-overlay", "url": "https://github.com/cptn-cosmo/dh-stream-overlay",
"manifest": "https://git.geeks.gay/cosmo/dh-stream-overlay/raw/branch/main/module.json", "manifest": "https://git.geeks.gay/cosmo/dh-stream-overlay/raw/branch/main/module.json",
"download": "https://git.geeks.gay/cosmo/dh-stream-overlay/releases/download/2.0.0/dh-stream-overlay.zip", "download": "https://git.geeks.gay/cosmo/dh-stream-overlay/releases/download/2.1.0/dh-stream-overlay.zip",
"description": "A stream overlay module for Daggerheart that displays chat and a linked party actor sheet." "description": "A stream overlay module for Daggerheart that displays chat and a linked party actor sheet."
} }

View file

@ -263,6 +263,27 @@ Hooks.once("init", () => {
onChange: () => { if (document.body.classList.contains("stream")) location.reload(); } onChange: () => { if (document.body.classList.contains("stream")) location.reload(); }
}); });
game.settings.register("dh-stream-overlay", "carouselDisableFade", {
name: "DH_STREAM_OVERLAY.Settings.CarouselDisableFade",
hint: "DH_STREAM_OVERLAY.Settings.CarouselDisableFadeHint",
scope: "world",
config: true,
type: Boolean,
default: false,
onChange: () => { if (document.body.classList.contains("stream")) location.reload(); }
});
game.settings.register("dh-stream-overlay", "carouselTransitionDuration", {
name: "DH_STREAM_OVERLAY.Settings.CarouselTransitionDuration",
hint: "DH_STREAM_OVERLAY.Settings.CarouselTransitionDurationHint",
scope: "world",
config: true,
type: Number,
default: 800,
range: { min: 200, max: 5000, step: 100 },
onChange: () => { if (document.body.classList.contains("stream")) location.reload(); }
});
game.settings.register("dh-stream-overlay", "carouselGMMode", { game.settings.register("dh-stream-overlay", "carouselGMMode", {
name: "DH_STREAM_OVERLAY.Settings.CarouselGMMode", name: "DH_STREAM_OVERLAY.Settings.CarouselGMMode",
hint: "DH_STREAM_OVERLAY.Settings.CarouselGMModeHint", hint: "DH_STREAM_OVERLAY.Settings.CarouselGMModeHint",
@ -278,6 +299,26 @@ Hooks.once("init", () => {
onChange: () => { if (document.body.classList.contains("stream")) location.reload(); } onChange: () => { if (document.body.classList.contains("stream")) location.reload(); }
}); });
game.settings.register("dh-stream-overlay", "carouselHidePlayers", {
name: "DH_STREAM_OVERLAY.Settings.CarouselHidePlayers",
hint: "DH_STREAM_OVERLAY.Settings.CarouselHidePlayersHint",
scope: "world",
config: true,
type: Boolean,
default: false,
onChange: () => { if (document.body.classList.contains("stream")) location.reload(); }
});
game.settings.register("dh-stream-overlay", "carouselHidePartyActor", {
name: "DH_STREAM_OVERLAY.Settings.CarouselHidePartyActor",
hint: "DH_STREAM_OVERLAY.Settings.CarouselHidePartyActorHint",
scope: "world",
config: true,
type: Boolean,
default: false,
onChange: () => { if (document.body.classList.contains("stream")) location.reload(); }
});
}); });
// ============================================================================= // =============================================================================
@ -504,10 +545,12 @@ function renderPartyOverlay(container) {
let carouselEnabled = false; let carouselEnabled = false;
let carouselEffect = "fade"; let carouselEffect = "fade";
let carouselGMMode = "cycle"; let carouselGMMode = "cycle";
let carouselHidePartyActor = false;
try { try {
carouselEnabled = game.settings.get("dh-stream-overlay", "carouselEnabled"); carouselEnabled = game.settings.get("dh-stream-overlay", "carouselEnabled");
carouselEffect = game.settings.get("dh-stream-overlay", "carouselEffect"); carouselEffect = game.settings.get("dh-stream-overlay", "carouselEffect");
carouselGMMode = game.settings.get("dh-stream-overlay", "carouselGMMode"); carouselGMMode = game.settings.get("dh-stream-overlay", "carouselGMMode");
carouselHidePartyActor = game.settings.get("dh-stream-overlay", "carouselHidePartyActor");
} catch (e) { } } catch (e) { }
const renderPips = (val, max, type) => { const renderPips = (val, max, type) => {
@ -578,6 +621,9 @@ function renderPartyOverlay(container) {
players.forEach(user => { players.forEach(user => {
const actor = user.character; const actor = user.character;
if (!actor) return; if (!actor) return;
// Filter Party Actor from Carousel if enabled
if (carouselEnabled && carouselHidePartyActor && actor.type.toLowerCase() === "party") return;
const system = actor.system || {}; const system = actor.system || {};
const items = actor.items; const items = actor.items;
@ -759,21 +805,36 @@ function renderPartyOverlay(container) {
let carouselClass = `carousel-mode effect-${carouselEffect}`; let carouselClass = `carousel-mode effect-${carouselEffect}`;
// GM Logic // GM Logic
// Check hide players setting
let hidePlayers = false;
try { hidePlayers = game.settings.get("dh-stream-overlay", "carouselHidePlayers"); } catch (e) { }
if (carouselGMMode === "static") { if (carouselGMMode === "static") {
// Static grid for GM, Carousel for Players // Static grid for GM, Carousel for Players
// Wrap in a flex container // Wrap in a flex container
container.innerHTML = ` container.innerHTML = `
<div class="dh-carousel-wrapper"> <div class="dh-carousel-wrapper">
${gms.length > 0 ? `<div class="dh-party-grid layout-${layoutMode} dh-static-gm">${gmHtml}</div>` : ""} ${gms.length > 0 ? `<div class="dh-party-grid layout-${layoutMode} dh-static-gm">${gmHtml}</div>` : ""}
${players.length > 0 ? `<div class="dh-party-grid layout-${layoutMode} ${carouselClass}">${playerHtml}</div>` : ""} ${(!hidePlayers && players.length > 0) ? `<div class="dh-party-grid layout-${layoutMode} ${carouselClass}">${playerHtml}</div>` : ""}
</div>`; </div>`;
} else if (carouselGMMode === "hidden") { } else if (carouselGMMode === "hidden") {
// Only Players in Carousel // Only Players in Carousel
if (!hidePlayers && players.length > 0) {
container.innerHTML = `<div class="dh-party-grid layout-${layoutMode} ${carouselClass}">${playerHtml}</div>`; container.innerHTML = `<div class="dh-party-grid layout-${layoutMode} ${carouselClass}">${playerHtml}</div>`;
} else {
container.innerHTML = ""; // Nothing to show
}
} else { } else {
// "cycle" or default - Mixed // "cycle" or default - Mixed
container.innerHTML = `<div class="dh-party-grid layout-${layoutMode} ${carouselClass}">${gmHtml}${playerHtml}</div>`; let mixedContent = gmHtml;
if (!hidePlayers) mixedContent += playerHtml;
if (mixedContent) {
container.innerHTML = `<div class="dh-party-grid layout-${layoutMode} ${carouselClass}">${mixedContent}</div>`;
} else {
container.innerHTML = "";
}
} }
} else { } else {
@ -1078,6 +1139,13 @@ function injectStyles() {
const useGreen = game.settings.get("dh-stream-overlay", "useGreenScreen"); const useGreen = game.settings.get("dh-stream-overlay", "useGreenScreen");
const autoExpand = game.settings.get("dh-stream-overlay", "autoExpandChat"); const autoExpand = game.settings.get("dh-stream-overlay", "autoExpandChat");
const hideActions = game.settings.get("dh-stream-overlay", "hideChatActions"); const hideActions = game.settings.get("dh-stream-overlay", "hideChatActions");
// New Carousel Settings
const carouselEffect = game.settings.get("dh-stream-overlay", "carouselEffect");
const disableFade = game.settings.get("dh-stream-overlay", "carouselDisableFade"); // Only applies if Slide usually
const transitionDuration = game.settings.get("dh-stream-overlay", "carouselTransitionDuration") || 800;
const durationSec = transitionDuration / 1000;
const bgColor = useGreen ? "#00ff00" : "rgba(0, 0, 0, 0)"; const bgColor = useGreen ? "#00ff00" : "rgba(0, 0, 0, 0)";
const style = document.createElement("style"); const style = document.createElement("style");
@ -1622,10 +1690,17 @@ function injectStyles() {
.dh-party-grid.carousel-mode .dh-party-card { .dh-party-grid.carousel-mode .dh-party-card {
grid-area: 1 / 1 / -1 / -1; /* Stack on top of each other */ grid-area: 1 / 1 / -1 / -1; /* Stack on top of each other */
opacity: 0;
/* Default State (Hidden/Exiting) */
${(disableFade && carouselEffect === 'slide') ? 'opacity: 1;' : 'opacity: 0;'}
visibility: hidden; visibility: hidden;
/* TRANSITION FIX: Delay visibility hide so it fades out first */ /* TRANSITION FIX: Delay visibility hide so it fades out first */
transition: opacity 0.8s ease-in-out, transform 0.8s ease-in-out, visibility 0s linear 0.8s; /* If Fade Disabled, we still need transition for Transform */
transition: ${(disableFade && carouselEffect === 'slide') ?
`transform ${durationSec}s ease-in-out, visibility 0s linear ${durationSec}s` :
`opacity ${durationSec}s ease-in-out, transform ${durationSec}s ease-in-out, visibility 0s linear ${durationSec}s`};
pointer-events: none; pointer-events: none;
width: 100%; width: 100%;
max-width: 600px; /* Constrain width in carousel */ max-width: 600px; /* Constrain width in carousel */
@ -1637,7 +1712,9 @@ function injectStyles() {
opacity: 1; opacity: 1;
visibility: visible; visibility: visible;
/* Show immediately */ /* Show immediately */
transition: opacity 0.8s ease-in-out, transform 0.8s ease-in-out, visibility 0s linear; transition: ${(disableFade && carouselEffect === 'slide') ?
`transform ${durationSec}s ease-in-out, visibility 0s linear` :
`opacity ${durationSec}s ease-in-out, transform ${durationSec}s ease-in-out, visibility 0s linear`};
pointer-events: auto; pointer-events: auto;
z-index: 10; z-index: 10;
transform: none; transform: none;
@ -1649,7 +1726,7 @@ function injectStyles() {
/* Slide */ /* Slide */
.dh-party-grid.carousel-mode.effect-slide .dh-party-card { .dh-party-grid.carousel-mode.effect-slide .dh-party-card {
transform: translateX(50px); transform: translateX(120%);
} }
.dh-party-grid.carousel-mode.effect-slide .dh-party-card.active-slide { .dh-party-grid.carousel-mode.effect-slide .dh-party-card.active-slide {
transform: translateX(0); transform: translateX(0);