diff --git a/src/macros_new/gowlers-tracking-ledger/foundry.gowlershome.dyndns.org/modules/gowlers-tracking-ledger/scripts/gowlers-tracking-ledger.js b/src/macros_new/gowlers-tracking-ledger/foundry.gowlershome.dyndns.org/modules/gowlers-tracking-ledger/scripts/gowlers-tracking-ledger.js index 3a7c802b..c62e38e5 100644 --- a/src/macros_new/gowlers-tracking-ledger/foundry.gowlershome.dyndns.org/modules/gowlers-tracking-ledger/scripts/gowlers-tracking-ledger.js +++ b/src/macros_new/gowlers-tracking-ledger/foundry.gowlershome.dyndns.org/modules/gowlers-tracking-ledger/scripts/gowlers-tracking-ledger.js @@ -1540,6 +1540,34 @@ function formatDamagePartsWithIcons(parts) { .join(" "); } +function renderDamageBar(composition = [], total = 0) { + const iconMap = { + slashing: { icon: "ra ra-sword", color: "#e3c000" }, + piercing: { icon: "ra ra-spear-head", color: "#2c7be5" }, + bludgeoning: { icon: "ra ra-large-hammer", color: "#e03131" }, + fire: { icon: "ra ra-fire", color: "#f76707" }, + cold: { icon: "ra ra-snowflake", color: "#3bc9db" }, + electricity: { icon: "ra ra-lightning-bolt", color: "#f0c419" }, + acid: { icon: "ra ra-round-bottom-flask", color: "#2f9e44" }, + sonic: { icon: "ra ra-megaphone", color: "#22b8cf" }, + force: { icon: "ra ra-crystal-ball", color: "#845ef7" }, + negative: { icon: "ra ra-skull", color: "#7950f2" }, + positive: { icon: "ra ra-sun", color: "#fab005" }, + precision: { icon: "ra ra-target-arrows", color: "#000" }, + nonlethal: { icon: "ra ra-hand", color: "#000" }, + untyped: { icon: "ra ra-uncertainty", color: "#666" }, + }; + if (!total || !composition.length) return ""; + const segments = composition.map((c) => { + const pct = Math.max(2, Math.round((c.value / total) * 100)); + const entry = iconMap[c.type?.toLowerCase?.()] ?? iconMap.untyped; + return `
+ +
`; + }); + return `
${segments.join("")}
`; +} + function resolveParticipantName(participant) { if (!participant) return "Unknown"; @@ -1695,13 +1723,37 @@ function computeDamageMeterData() { const filtered = currentEncounterId ? entries.filter((e) => e.encounterId === currentEncounterId) : entries; if (!filtered.length) continue; - const total = filtered.reduce((sum, e) => sum + (Number(e.amount) || 0), 0); + const typeTotals = new Map(); + let total = 0; + for (const e of filtered) { + const amount = Number(e.amount) || 0; + total += amount; + const parts = e.damageDetails?.parts; + if (Array.isArray(parts) && parts.length) { + for (const p of parts) { + const t = (p.types && p.types[0]) || p.customTypes?.[0] || p.materials?.[0] || "untyped"; + const prev = typeTotals.get(t) ?? 0; + typeTotals.set(t, prev + (Number(p.total) || 0)); + } + } else { + const prev = typeTotals.get("untyped") ?? 0; + typeTotals.set("untyped", prev + amount); + } + } + + const composition = Array.from(typeTotals.entries()) + .map(([type, value]) => ({ type, value })) + .sort((a, b) => b.value - a.value); + + const img = actor.prototypeToken?.texture?.src || actor.img || ""; totals.push({ actorId: actor.id, name: actor.name, total, hits: filtered.length, last: filtered[0], + img, + composition, }); } @@ -1721,16 +1773,16 @@ function buildDamageMeterContent() { (t, idx) => { const max = totals[0]?.total || 1; const pct = Math.max(1, Math.round((t.total / max) * 100)); + const bar = renderDamageBar(t.composition, t.total) || `
`; + const avatar = t.img ? `` : ""; return ` ${idx + 1} - ${t.name} + ${avatar}${t.name} ${t.total} ${t.hits} -
-
-
+ ${bar} ${t.last?.breakdown ?? ""} `;